{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N7ITxKLUkX0v"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "yOYx6tzSnWQ3"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6xgB0Oz5eGSQ"
      },
      "source": [
        "# 그래프 및 함수 소개"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "w4zzZVZtQb1w"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td><a target=\"_blank\" href=\"https://www.tensorflow.org/guide/intro_to_graphs\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org에서 보기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ko/guide/intro_to_graphs.ipynb\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab에서 실행하기</a></td>\n",
        "  <td><a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ko/guide/intro_to_graphs.ipynb\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub에서소스 보기</a></td>\n",
        "  <td><a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ko/guide/intro_to_graphs.ipynb\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">노트북 다운로드하기</a></td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RBKqnXI9GOax"
      },
      "source": [
        "# 그래프 및 `tf.function` 소개\n",
        "\n",
        "이 가이드는 TensorFlow 및 Keras의 내부를 살펴봄으로써 TensorFlow의 동작 방식을 알아봅니다. 대신 Keras를 바로 시작하려면 [Keras 가이드 모음](keras/)을 참조하세요.\n",
        "\n",
        "이 가이드에서는 TensorFlow 코드를 간단하게 변경하여 그래프를 가져오는 방법, 그래프를 저장하고 표현하는 방법, 그리고 그래프를 사용하여 모델의 속도를 높이고 내보내는 방법의 핵심을 살펴봅니다.\n",
        "\n",
        "참고: TensorFlow 1.x에만 익숙한 사용자를 위해 이 가이드는 매우 다른 그래프 뷰를 보여줍니다.\n",
        "\n",
        "이 가이드는 짧은 형식의 소개입니다. 개념에 대한 전체 소개는 [`tf.function` 가이드](function)를 참조하세요.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v0DdlfacAdTZ"
      },
      "source": [
        "## 그래프란 무엇인가요?\n",
        "\n",
        "이전의 3가지 가이드에서 TensorFlow가 **즉시(eagerly)** 실행되는 것을 보았습니다. 이는 TensorFlow 연산이 Python에 의해 실행되고 연산별로 결과가 다시 Python으로 반환됨을 의미합니다. Eager TensorFlow는 GPU의 장점을 활용하여 GPU와 TPU에 변수, 텐서 및 연산을 배치할 수 있습니다. 디버깅도 쉽습니다.\n",
        "\n",
        "일부 사용자의 경우 Python가 전혀 필요하지 않거나 Python을 아예 떠나고 싶을 수도 있습니다.\n",
        "\n",
        "그러나 Python에서 TensorFlow를 연산별로 실행하면 여러 가속 기능을 사용할 수 없습니다. Python에서 텐서 계산을 추출할 수 있다면 *그래프*로 만들 수 있습니다.\n",
        "\n",
        "**그래프는 계산의 단위를 나타내는 `tf.Operation` 객체와 연산 간에 흐르는 데이터의 단위를 나타내는 `tf.Tensor` 객체의 세트를 포함합니다.** 데이터 구조는 `tf.Graph` 컨텍스트에서 정의됩니다. 그래프는 데이터 구조이므로 원래 Python 코드 없이 모두 저장, 실행 및 복원할 수 있습니다.\n",
        "\n",
        "다음은 TensorBoard에서 시각화되었을 때의 2계층 그래프의 간단한 모습입니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FvQ5aBuRGT1o"
      },
      "source": [
        "![2 층 텐서 플로우 그래프](https://storage.cloud.google.com/tensorflow.org/images/two-layer-network.png)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DHpY3avXGITP"
      },
      "source": [
        "## 그래프의 이점\n",
        "\n",
        "그래프를 사용하면 유연성이 크게 향상됩니다. 모바일 애플리케이션, 임베디드 기기 및 백엔드 서버와 같은 Python 인터프리터가 없는 환경에서 TensorFlow 그래프를 사용할 수 있습니다. TensorFlow는 그래프를 Python에서 내보낼 때 저장된 모델의 형식으로 그래프를 사용합니다.\n",
        "\n",
        "그래프는 쉽게 최적화되어 컴파일러가 다음과 같은 변환을 수행할 수 있습니다.\n",
        "\n",
        "- 계산에서 상수 노드를 접어 텐서의 값을 정적으로 추론합니다*(\"일정한 접기\")*.\n",
        "- 독립적인 계산의 하위 부분을 분리하여 스레드 또는 기기 간에 분할합니다.\n",
        "- 공통 하위 표현식을 제거하여 산술 연산을 단순화합니다.\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o1x1EOD9GjnB"
      },
      "source": [
        "위와 같은 변환 및 기타 속도 향상을 수행하기 위한 전체 최적화 시스템으로 [Grappler](./graph_optimization.ipynb)가 있습니다.\n",
        "\n",
        "요약하면, 그래프는 TensorFlow가 **빠르게**, **병렬로**, 그리고 효율적으로 **여러 기기에서** 실행할 때 아주 유용합니다.\n",
        "\n",
        "그러나 편의를 위해 Python에서 머신러닝 모델(또는 기타 계산)을 정의한 다음 필요할 때 자동으로 그래프를 구성하려고 합니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pSZebVuWxDXu"
      },
      "source": [
        "# 그래프 추적하기\n",
        "\n",
        "TensorFlow에서 그래프를 생성하는 방법은 `tf.function`을 직접 호출 또는 데코레이터로 사용하는 것입니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "goZwOXp_xyQj"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "import timeit\n",
        "from datetime import datetime"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HKbLeJ1y0Umi"
      },
      "outputs": [],
      "source": [
        "# Define a Python function\n",
        "def function_to_get_faster(x, y, b):\n",
        "  x = tf.matmul(x, y)\n",
        "  x = x + b\n",
        "  return x\n",
        "\n",
        "# Create a `Function` object that contains a graph\n",
        "a_function_that_uses_a_graph = tf.function(function_to_get_faster)\n",
        "\n",
        "# Make some tensors\n",
        "x1 = tf.constant([[1.0, 2.0]])\n",
        "y1 = tf.constant([[2.0], [3.0]])\n",
        "b1 = tf.constant(4.0)\n",
        "\n",
        "# It just works!\n",
        "a_function_that_uses_a_graph(x1, y1, b1).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MT7U8ozok0gV"
      },
      "source": [
        "`tf.function`화된 함수는 해당 Python과 같게 동작하는 [Python callable]()입니다. Python callable은 특정 클래스(`python.eager.def_function.Function`)을 갖지만, 비 추적 버전과 같이 동작합니다.\n",
        "\n",
        "`tf.function`은 호출하는 모든 Python 함수를 재귀적으로 추적합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rpz08iLplm9F"
      },
      "outputs": [],
      "source": [
        "def inner_function(x, y, b):\n",
        "  x = tf.matmul(x, y)\n",
        "  x = x + b\n",
        "  return x\n",
        "\n",
        "# Use the decorator\n",
        "@tf.function\n",
        "def outer_function(x):\n",
        "  y = tf.constant([[2.0], [3.0]])\n",
        "  b = tf.constant(4.0)\n",
        "\n",
        "  return inner_function(x, y, b)\n",
        "\n",
        "# Note that the callable will create a graph that\n",
        "# includes inner_function() as well as outer_function()\n",
        "outer_function(tf.constant([[1.0, 2.0]])).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "P88fOr88qgCj"
      },
      "source": [
        "TensorFlow 1.x를 사용하면, `Placeholder` 또는 `tf.Sesssion`을 정의할 필요가 없었음을 알 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wfeKf0Nr1OEK"
      },
      "source": [
        "## 흐름 제어 및 부작용\n",
        "\n",
        "흐름 제어 및 루프는 기본적으로 `tf.autograph`를 통해 TensorFlow로 변환됩니다. Autograph는 루프 구성의 표준화, 언롤링 및 [AST](https://docs.python.org/3/library/ast.html) 조작을 포함하여 메서드의 조합을 사용합니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PFObpff1BMEb"
      },
      "outputs": [],
      "source": [
        "def my_function(x):\n",
        "  if tf.reduce_sum(x) <= 1:\n",
        "    return x * x\n",
        "  else:\n",
        "    return x-1\n",
        "\n",
        "a_function = tf.function(my_function)\n",
        "\n",
        "print(\"First branch, with graph:\", a_function(tf.constant(1.0)).numpy())\n",
        "print(\"Second branch, with graph:\", a_function(tf.constant([5.0, 5.0])).numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hO4DBUNZBMwQ"
      },
      "source": [
        "Autograph 변환을 직접 호출하여 Python이 TensorFlow ops로 어떻게 변환되는지 확인할 수 있습니다. 대부분 읽을 수 없지만, 변환을 볼 수는 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8x6RAqza1UWf"
      },
      "outputs": [],
      "source": [
        "# Don't read the output too carefully.\n",
        "print(tf.autograph.to_code(my_function))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GZ4Ieg6tBE6l"
      },
      "source": [
        "Autograph는 자동으로 `if-then` 절, 루프, `break`, `return`, `continue` 등을 변환합니다.\n",
        "\n",
        "대부분의 경우, Autograph는 특별한 고려 없이 동작합니다. 그러나 몇 가지 주의 사항이 있으며, [tf.function 가이드](./function.ipynb)와 [전체 autograph 참조](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/autograph/g3doc/reference/index.md)가 도움이 될 수 있습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A6NHDp7vAKcJ"
      },
      "source": [
        "## 속도 향상\n",
        "\n",
        "`tf.function`에서 텐서를 사용하는 함수를 래핑하는 것만으로는 코드의 속도를 자동으로 높일 수 없습니다. 단일 기기에서 몇 번 호출되는 작은 함수의 경우, 그래프나 그래프 조각 호출의 오버헤드가 런타임의 대부분을 차지할 수도 있습니다. 또한, GPU를 많이 사용하는 컨볼루션과 같이 대부분의 계산이 가속기에서 이미 발생한 경우, 그래프의 속도 향상은 크지 않을 것입니다.\n",
        "\n",
        "복잡한 계산의 경우, 그래프는 상당한 속도 향상을 제공할 수 있습니다. 그래프는 Python과 기기 간 통신을 줄이고 일부 속도 향상을 수행하기 때문입니다.\n",
        "\n",
        "다음 코드는 일부 작은 밀집 레이어에서 몇 번 실행됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zbNndv-0BeO4"
      },
      "outputs": [],
      "source": [
        "# Create an oveerride model to classify pictures\n",
        "class SequentialModel(tf.keras.Model):\n",
        "  def __init__(self, **kwargs):\n",
        "    super(SequentialModel, self).__init__(**kwargs)\n",
        "    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))\n",
        "    self.dense_1 = tf.keras.layers.Dense(128, activation=\"relu\")\n",
        "    self.dropout = tf.keras.layers.Dropout(0.2)\n",
        "    self.dense_2 = tf.keras.layers.Dense(10)\n",
        "\n",
        "  def call(self, x):\n",
        "    x = self.flatten(x)\n",
        "    x = self.dense_1(x)\n",
        "    x = self.dropout(x)\n",
        "    x = self.dense_2(x)\n",
        "    return x\n",
        "\n",
        "input_data = tf.random.uniform([60, 28, 28])\n",
        "\n",
        "eager_model = SequentialModel()\n",
        "graph_model = tf.function(eager_model)\n",
        "\n",
        "print(\"Eager time:\", timeit.timeit(lambda: eager_model(input_data), number=10000))\n",
        "print(\"Graph time:\", timeit.timeit(lambda: graph_model(input_data), number=10000))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kNGuLnjK1c5U"
      },
      "source": [
        "### 다형 함수\n",
        "\n",
        "함수를 추적할 때 생성하는 `Function` 객체는 **polymorphic**입니다. 다형 함수는 하나의 API 뒤에서 몇 가지 concrete 함수 그래프를 캡슐화하는 Python callable입니다.\n",
        "\n",
        "이 `Function`은 모든 종류의 `dtypes`과 형상에 사용할 수 있습니다. 새로운 인수 서명을 사용하여 호출할 때마다 원래 함수는 새로운 인수로 다시 추적됩니다. 그런 다음 `Function`은 `concrete_function`에서의 추적에 해당하는 `tf.Graph`를 저장합니다. 함수가 이미 해당 종류의 인수로 추적되었다면, 미리 추적된 그래프를 얻습니다.\n",
        "\n",
        "개념적으로, 다음과 같습니다.\n",
        "\n",
        "- **`tf.Graph`**는 계산을 설명하는 원시 휴대용 데이터 구조입니다.\n",
        "- **`Function`**은 ConcreteFunctions에 대한 캐싱, 추적, 디스패처입니다.\n",
        "- **`ConcreteFunction`**은 Python에서 그래프를 실행할 수 있는 그래프의 eager 호환 래퍼입니다.\n",
        "\n",
        "### 다형 함수 검사하기\n",
        "\n",
        "Python 함수 `my_function`에서 `tf.function` 호출의 결과인 `a_function`을 검사할 수 있습니다. 다음 예제에서는 3가지 종류의 인수를 사용하여 `a_function`을 호출하면 3가지 concrete 함수가 생성됩니다.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "7heuYuwn2edE"
      },
      "outputs": [],
      "source": [
        "print(a_function)\n",
        "\n",
        "print(\"Calling a `Function`:\")\n",
        "print(\"Int:\", a_function(tf.constant(2)))\n",
        "print(\"Float:\", a_function(tf.constant(2.0)))\n",
        "print(\"Rank-1 tensor of floats\", a_function(tf.constant([2.0, 2.0, 2.0])))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "s1c8db0cCW2k"
      },
      "outputs": [],
      "source": [
        "# Get the concrete function that works on floats\n",
        "print(\"Inspecting concrete functions\")\n",
        "print(\"Concrete function for float:\")\n",
        "print(a_function.get_concrete_function(tf.TensorSpec(shape=[], dtype=tf.float32)))\n",
        "print(\"Concrete function for tensor of floats:\")\n",
        "print(a_function.get_concrete_function(tf.constant([2.0, 2.0, 2.0])))\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JLTNuv_CCZXK"
      },
      "outputs": [],
      "source": [
        "# Concrete functions are callable\n",
        "# Note: You won't normally do this, but instead just call the containing `Function`\n",
        "cf = a_function.get_concrete_function(tf.constant(2))\n",
        "print(\"Directly calling a concrete function:\", cf(tf.constant(2)))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PTHNiHLXH9es"
      },
      "source": [
        "이 예제에서는 스택에 상당히 근접한 것을 볼 수 있습니다. 추적을 구체적으로 관리하지 않는 한, 일반적으로 여기에 표시된 concrete 함수를 직접 호출할 필요는 없습니다."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V11zkxU22XeD"
      },
      "source": [
        "# 즉시 실행으로 되돌리기\n",
        "\n",
        "`tf.Graph`를 참조하거나 `tf.Graph().as_default()`를 사용하여 참조하는 경우와 같이 긴 스택 추적을 만나게 될 수도 있습니다. 이는 그래프 컨텍스트에서 실행 중일 가능성이 있음을 의미합니다. TensorFlow의 핵심 함수는 Keras의 `model.fit()`과 같은 그래프 컨텍스트를 사용합니다.\n",
        "\n",
        "즉시 실행을 디버깅하는 것이 훨씬 쉬운 경우가 많습니다. 스택 추적은 비교적 짧고 이해하기 쉬워야 합니다.\n",
        "\n",
        "그래프에서 디버깅이 까다로워지는 상황에서는 즉시 실행을 사용하여 되돌린 후 디버깅할 수 있습니다.\n",
        "\n",
        "즉시 실행을 확인하는 방법은 다음과 같습니다.\n",
        "\n",
        "- 모델과 레이어를 callable로 직접 호출\n",
        "\n",
        "- 컴파일에서 Keras compile/fit 사용 시, **`model.compile(run_eagerly=True)`** 사용\n",
        "\n",
        "- **`tf.config.run_functions_eagerly(True)`**를 통해 전역 실행 모드 설정\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "iTHvdQfRICJb"
      },
      "source": [
        "### `run_eagerly=True` 사용하기"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "kqzBV2rSzvpC"
      },
      "outputs": [],
      "source": [
        "# Define an identity layer with an eager side effect\n",
        "class EagerLayer(tf.keras.layers.Layer):\n",
        "  def __init__(self, **kwargs):\n",
        "    super(EagerLayer, self).__init__(**kwargs)\n",
        "    # Do some kind of initialization here\n",
        "\n",
        "  def call(self, inputs):\n",
        "    print(\"\\nCurrently running eagerly\", str(datetime.now()))\n",
        "    return inputs"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "5DFvc9ySr7t3"
      },
      "outputs": [],
      "source": [
        "# Create an override model to classify pictures, adding the custom layer\n",
        "class SequentialModel(tf.keras.Model):\n",
        "  def __init__(self):\n",
        "    super(SequentialModel, self).__init__()\n",
        "    self.flatten = tf.keras.layers.Flatten(input_shape=(28, 28))\n",
        "    self.dense_1 = tf.keras.layers.Dense(128, activation=\"relu\")\n",
        "    self.dropout = tf.keras.layers.Dropout(0.2)\n",
        "    self.dense_2 = tf.keras.layers.Dense(10)\n",
        "    self.eager = EagerLayer()\n",
        "\n",
        "  def call(self, x):\n",
        "    x = self.flatten(x)\n",
        "    x = self.dense_1(x)\n",
        "    x = self.dropout(x)\n",
        "    x = self.dense_2(x)\n",
        "    return self.eager(x)\n",
        "\n",
        "# Create an instance of this model\n",
        "model = SequentialModel()\n",
        "\n",
        "# Generate some nonsense pictures and labels\n",
        "input_data = tf.random.uniform([60, 28, 28])\n",
        "labels = tf.random.uniform([60])\n",
        "\n",
        "loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "U3-hcwmpI3Sv"
      },
      "source": [
        "먼저, eager 없이 모델을 컴파일하세요. 모델은 추적되지 않습니다. `compile`은 손실 함수, 최적화 및 기타 훈련 매개변수만 설정합니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "w2GdwhB_KQlw"
      },
      "outputs": [],
      "source": [
        "model.compile(run_eagerly=False, loss=loss_fn)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WLMXk1uxKQ44"
      },
      "source": [
        "이제 `fit`을 호출하고 함수가 추적되고(두 번) eager 효과가 다시 실행되지 않는지 확인하세요."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "VCoLlZDythZ8"
      },
      "outputs": [],
      "source": [
        "model.fit(input_data, labels, epochs=3)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "jOk6feLOK1pR"
      },
      "source": [
        "그러나 eager에서 단 한 번의 epoch만 실행해도 eager 부작용을 두 번 볼 수 있습니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "MGIYwrKpK06e"
      },
      "outputs": [],
      "source": [
        "print(\"Running eagerly\")\n",
        "# When compiling the model, set it to run eagerly\n",
        "model.compile(run_eagerly=True, loss=loss_fn)\n",
        "\n",
        "model.fit(input_data, labels, epochs=1)\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qwq_cnc8Lwf8"
      },
      "source": [
        "### `run_functions_eagerly` 사용하기\n",
        "\n",
        "모든 것을 즉시 실행하도록 전역적으로 설정할 수도 있습니다. 재추적할 때만 동작합니다. 추적된 함수는 추적된 상태로 그래프로 실행됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oFSxRtcptYpe"
      },
      "outputs": [],
      "source": [
        "# Now, globally set everything to run eagerly\n",
        "tf.config.experimental_run_functions_eagerly(True)\n",
        "print(\"Run all functions eagerly.\")\n",
        "\n",
        "# First, trace the model, triggering the side effect\n",
        "polymorphic_function = tf.function(model)\n",
        "\n",
        "# It was traced...\n",
        "print(polymorphic_function.get_concrete_function(input_data))\n",
        "\n",
        "# But when you run the function again, the side effect happens (both times).\n",
        "result = polymorphic_function(input_data)\n",
        "result = polymorphic_function(input_data)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "pD-AQxEhua4E"
      },
      "outputs": [],
      "source": [
        "# Don't forget to set it back when you are done\n",
        "tf.config.experimental_run_functions_eagerly(False)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sm0bNFp8PX53"
      },
      "source": [
        "# 추적 및 성능\n",
        "\n",
        "추적에는 약간의 오버헤드가 발생합니다. 작은 함수를 추적하는 것은 빠르지만 큰 모델은 추적하는 데 시간이 오래 걸릴 수 있습니다. 이러한 노력은 일반적으로 성능 향상으로 신속하게 이어지지만, 대형 모델의 훈련에서 처음 몇 번의 epoch가 추적으로 인해 느려질 수 있다는 점에 유의해야 합니다.\n",
        "\n",
        "모델 크기와 관계없이, 빈번한 추적은 피해야 합니다. [tf.function 가이드의 이 섹션](function.ipynb#when_to_retrace)은 재추적을 피하기 위해 입력 명세를 설정하는 방법과 텐서 인수를 사용하는 방법에 관해 설명합니다. 비정상적으로 성능이 저하되고 있음을 발견하면, 실수로 재추적을 하고 있지 않은지 확인하는 것이 좋습니다.\n",
        "\n",
        "함수가 언제 추적되는지 확인할 수 있도록 eager 부작용(예: Python 인수 인쇄)을 추가할 수 있습니다. 새로운 Python 인수가 항상 재추적을 트리거 하기 때문에 추가 재추적이 표시됩니다."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jsGQ4GQAP2Ve"
      },
      "outputs": [],
      "source": [
        "# Use @tf.function decorator\n",
        "@tf.function\n",
        "def a_function_with_python_side_effect(x):\n",
        "  print(\"Tracing!\")  # This eager\n",
        "  return x * x + tf.constant(2)\n",
        "\n",
        "# This is traced the first time\n",
        "print(a_function_with_python_side_effect(tf.constant(2)))\n",
        "# The second time through, you won't see the side effect\n",
        "print(a_function_with_python_side_effect(tf.constant(3)))\n",
        "\n",
        "# This retraces each time the Python argument chances\n",
        "# as a Python argument could be an epoch count or other\n",
        "# hyperparameter\n",
        "print(a_function_with_python_side_effect(2))\n",
        "print(a_function_with_python_side_effect(3))\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "D1kbr5ocpS6R"
      },
      "source": [
        "# 다음 단계\n",
        "\n",
        "`tf.function`API 참조 페이지 및 [가이드](./function.ipynb)에서 자세한 내용을 읽을 수 있습니다."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "intro_to_graphs.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
